package org.common.utils.tool;
import java.io.File;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;

/**
 * 字符串工具
 * @author zhouzhibing
 * @date 2024/11/27
 */
public class StringTool {
    /**
     * 系统文件目录分隔符
     */
    public static final String SEPARATOR = File.separator;

    /**
     * 系统文件目录分隔符（带转义符)
     */
    public static final String SEPARATOR_ESCAPE = "\\" + File.separator;

    /**
     * [a-zA-Z0-9_]：匹配单个字母（大小写）、数字或下划线
     */
    public static final String REGEX = "^\\w+$";

    /**
     * 检查一个字符串，是否为空
     * @param content 字符串内容
     * @return 是否为空
     */
    public static boolean isEmpty(String content) {
        return content == null || content.isEmpty();
    }

    /**
     * 将一个字符串，转成小写的字符串。
     * @param content 待转字符串
     * @return 返回转小写的字符串。
     */
    public static String toMinString(String content) {
        return content.toLowerCase();
    }

    /**
     * 验证一个字符串，是否为有效的字符串。
     * 正则表达式：仅包含字母/数字/下划线，且长度至少为1
     * @param content 待验证的字符串
     * @return 返回一个有效的字符串。
     */
    public static boolean isValidString(String content) {
        if (isEmpty(content)) {
            return false;
        }
        return Pattern.matches(REGEX, content);
    }

    /**
     * 将一个字符串，转成List<String>。
     * @param content 待转字符串
     * @param split 分割符
     * @return 返回一个不可修改的List<String>
     */
    public static List<String> splitStringList(String content , String split) {
        return splitList(content , split , string -> string);
    }

    /**
     * 将一个字符串，转成List<Integer>。
     * @param content 待转字符串
     * @param split 分割符
     * @return 返回一个不可修改的List<Integer>
     */
    public static List<Integer> splitIntList(String content , String split) {
        return splitList(content , split , Integer::parseInt);
    }

    /**
     * 将一个字符串，转成List<T>。
     * @param content 待转字符串
     * @param split 分割符
     * @param function 转换函数
     * @return 返回一个不可修改的List<T>
     * @param <T> 转换的类型
     */
    public static <T> List<T> splitList(String content , String split , Function<String , T> function) {
        if(isEmpty(content))
            return List.of();

        String[] array = content.split(split);
        List<T> list = new ArrayList<>(array.length);

        for (String string : array) {
            T t = function.apply(string);
            list.add(t);
        }
        return Collections.unmodifiableList(list);
    }


    /**
     * 将一个字符串，转成蛇形命名的规范的字符串。
     * @param content 待转字符串
     * @return 返回转换后的蛇形命名规范的字符串。
     */
    public static String toSnakeString(String content) {
        StringBuilder newStringBuilder = new StringBuilder();
        for (int i = 0; i < content.length(); i++) {
            char currentChar = content.charAt(i);
            if (Character.isUpperCase(currentChar)) {
                if (i > 0) {
                    newStringBuilder.append("_");
                }
                newStringBuilder.append(Character.toLowerCase(currentChar));
            } else {
                newStringBuilder.append(currentChar);
            }
        }
        return newStringBuilder.toString();
    }

    /**
     * 将一个字段串，蛇形命名转小驼峰命名（首字母小写，后面首字母全大写）
     * @param string 待转字符串
     * @return 返回转换后的小驼峰命名规范的字符串
     */
    public static String toMinHumpString(String string) {
        if(string.contains("_")) {
            StringBuilder stringBuilder = new StringBuilder();
            String[] str = string.split("_");
            for (String string2 : str) {
                if(stringBuilder.isEmpty()) {
                    String firstChar = string2.substring(0, 1);
                    string2 = string2.replaceFirst(firstChar, firstChar.toLowerCase());
                    stringBuilder.append(string2);
                } else {
                    stringBuilder.append(string2.substring(0, 1).toUpperCase());
                    stringBuilder.append(string2.substring(1));
                }
            }
            return stringBuilder.toString().trim();
        } else {
            String firstChar = string.substring(0, 1);
            return string.replaceFirst(firstChar, firstChar.toLowerCase());
        }
    }

    /**
     * 将一个字段串, 蛇形命名转 大驼峰命名（首字母全大写）
     * @param string 待转字符串
     * @return 返回转换后的大驼峰命名规范的字符串
     */
    public static String toMaxHumpString(String string) {
        if(string.contains("_")) {
            StringBuilder stringBuilder = new StringBuilder();
            String[] str = string.split("_");
            for (String string2 : str) {
                stringBuilder.append(string2.substring(0, 1).toUpperCase());
                stringBuilder.append(string2.substring(1));
            }
            return stringBuilder.toString().trim();
        } else {
            String firstChar = string.substring(0,1);
            return string.replaceFirst(firstChar, firstChar.toUpperCase());
        }
    }

    public static void byIndexString(StringBuilder stringBuilder , String value , String split, int curIndex , int endIndex) {
        byIndexString(stringBuilder , null , value , null , split , curIndex , endIndex);
    }

    public static void byIndexString(StringBuilder stringBuilder , String leftString ,String value , String rightString, String split, int curIndex , int endIndex) {
        if(leftString != null)
            stringBuilder.append(leftString);
        stringBuilder.append(value);
        if(rightString != null)
            stringBuilder.append(rightString);
        if(curIndex < endIndex)
            stringBuilder.append(split);
    }

    /**
     * 返回数据库对应java类型的字符串
     * @param columnType 列类型
     * @return java类型的字符串
     */
    public static String getJavaTypeString(String columnType) {
        String typeString = columnType.toLowerCase();
        if("tinyint(1)".equals(typeString))
            return "boolean";

        int index = typeString.indexOf("(");
        if(index >= 0)
            typeString = typeString.substring(0 , index);
        return switch (typeString) {
            case "varchar", "mediumtext", "text", "char", "longtext", "string", "String" -> "String";
            case "bigint" -> "long";
            case "int", "integer" -> "int";
            case "float" -> "float";
            case "double" -> "double";
            case "tinyint" -> "byte";
            case "bit", "bool" , "boolean" -> "boolean";
            case "blob", "longblob" -> "byte []";
            case "decimal" -> "java.math.BigDecimal";
            case "timestamp" -> "java.sql.Timestamp";
            case "datetime", "date" -> "java.sql.Date";
            case "time" -> "java.sql.Time";
//            case "json" -> "com.alibaba.fastjson2.JSONObject";
            case "json" -> "String";
            default -> throw new RuntimeException("not java type , columnType = " + columnType);
        };
    }

    /**
     * 初始化map中的引用值，会把${name}引用替换成存在的属性值。
     * @param map 配置map对象
     */
    public static void initReference(Map<String, String> map) {
        for (Map.Entry<String , String> entry : map.entrySet()) {
            String key = entry.getKey();
            String valueString = entry.getValue();

            int start = valueString.indexOf("${");
            if(start >= 0) {
                int end = valueString.indexOf("}");
                while(start >= 0) {
                    String refKey = valueString.substring(start + 2, end);
                    String refValue = map.get(refKey);
                    if(refValue == null)
                        break;
                    valueString = valueString.replaceAll("\\$\\{"+refKey+"\\}", refValue);
                    map.put(key, valueString);

                    start = valueString.indexOf("${");
                    end = valueString.indexOf("}");
                }
            }
        }
    }

    /**
     * 将字符串值转换成对应类型的值
     * @param type 类型
     * @param valueString 配置文件内容
     * @return 对应类型的值
     */
    public static Object toTypeValue(Class<?> type, String valueString) {
        if (type == String.class) {
            return valueString;
        } else if (type == int.class || type == Integer.class) {
            return Integer.valueOf(valueString);
        } else if (type == long.class || type == Long.class) {
            return Long.valueOf(valueString);
        } else if (type == boolean.class || type == Boolean.class) {
            return Boolean.valueOf(valueString);
        } else if (type == float.class || type == Float.class) {
            return Float.valueOf(valueString);
        }
        return valueString;
    }
}
